﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BonsaiScrum.Core.Persistance;
using BonsaiScrum.Core.Domain.Shared;
using NHibernate;

namespace BonsaiScrum.Data
{
    public sealed class NHibernateDomainRepository : IDomainRepository, IDisposable
    {
        private ISession _session;
        private ITransaction _transaction;

        public NHibernateDomainRepository(ISession session)
        {
            if (session == null)
                throw new ArgumentNullException("session");

            _session = session;
        }

        public TEntity GetById<TEntity>(int id) where TEntity : BaseEntity<TEntity>
        {
            return _session.Get<TEntity>(id);
        }

        public void Add<TEntity>(TEntity entity) where TEntity : BaseEntity<TEntity>
        {
            if (_session == null) throw new InvalidOperationException("Session must be open before an entity may be saved or updated.");
            if (_transaction == null) throw new InvalidOperationException("Saves or updates must be done within a transaction.");
            _session.SaveOrUpdate(entity);
        }

        public void BeginTransaction()
        {
            if (!SessionIsOpen) throw new InvalidOperationException("Session must be open before a transaction can be started.");

            if (_transaction == null)
                _transaction = _session.BeginTransaction();
        }

        private bool SessionIsOpen
        {
            get
            {
                if (_session == null) return false;

                return _session.IsOpen;
            }
        }

        public void Commit()
        {
            if (_session == null) throw new InvalidOperationException("Session must be open before a transaction may be committed.");
            if (_transaction == null) throw new InvalidOperationException("Session must have an open transaction to be able to commit.");

            _transaction.Commit();
            _transaction = null;
            
        }

        public void Rollback()
        {
            if (_session == null) throw new InvalidOperationException("Session must be open before a transaction may be rolled back.");

            if (_transaction != null)
            {
                _transaction.Rollback();
                _transaction = null;
            }
        }

        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool isDisposing)
        {
            if (isDisposing)
            {
                if (_transaction != null)
                {
                    if (_transaction.IsActive) 
                        _transaction.Commit();
                    _transaction.Dispose();
                    _transaction = null;
                }

                if (_session != null)
                {
                    if (_session.IsConnected) _session.Disconnect();
                    if (_session.IsOpen) _session.Close();

                    _session.Dispose();
                    _session = null;
                }
            }
        }
    }
}
